﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Modeling;
using VsxFactory.Modeling.VisualStudio;
using VsxFactory.Modeling.Repository;

namespace VsxFactory.Modeling.Strategies
{
    /// <summary>
    /// Contexte d'excution de la strategie lors de la generation
    /// </summary>
    public abstract class StrategyContext : MarshalByRefObject, IStrategyContext
    {
        /// <summary>
        /// Constructeur
        /// </summary>
        /// <param name="strategy">Strategie courante</param>
        /// <param name="serviceProvider">Service provider du contexte courant</param>
        /// <param name="modelFileName">Chemin du modéle sur lequel porte la génération</param>
        /// <param name="generationEvent">Type d'événement ayant entrainé la génération</param>
        public StrategyContext(IServiceProvider serviceProvider)
        {
            System.Diagnostics.Contracts.Contract.Requires(serviceProvider != null);
            ServiceProvider = serviceProvider;
            InitializeRepository(); 
        }

        public virtual void SetContextForStrategy(IGenerationStrategy strategy, IVsProjectFileItem model, CodeGenerationEvent generationEvent )
        {
            if( model != null) ModelFileName = model.Path;
            GenerationEvent = generationEvent;
            this.Strategy = strategy;
            InitializeRepository();
        }

        private void InitializeRepository() {
            LocalRepository = CreateLocalRepository();
            SolutionRepository = CreateSolutionRepository();
        }

        protected abstract IStandardPackageRepository CreateLocalRepository();
        protected abstract ReferencePackageRepository CreateSolutionRepository();

        public IStandardPackageRepository LocalRepository { get; private set; }
        public ReferencePackageRepository SolutionRepository { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetService<T>()
        {
            return (T)ServiceProvider.GetService(typeof(T));
        }

        public TService GetService<TKey, TService>()
        {
            return (TService)ServiceProvider.GetService(typeof(TKey));
        }

        public abstract void ClearErrors();

        /// <summary>
        /// Affichage d'un message dans le log
        /// </summary>
        /// <param name="format">Format du message</param>
        /// <param name="parms">Paramètres du format de message</param>
        public abstract void WriteLogMessage(string format, params object[] parms);

        public abstract bool PromptYesNo(string text);

        public abstract IProgressDialog ShowProgressDialog(string title, string text);

        /// <summary>
        /// Affiche une erreur
        /// </summary>
        /// <param name="format">Format du message</param>
        /// <param name="parms">Paramètres du format de message</param>
        public abstract void WriteError(string format, params object[] parms);

        public abstract IStrategySettings  Settings { get;}
        public abstract IVsSolutionExplorer SolutionExplorer {get;}

        /// <summary>
        /// Evenement à l'origine de la génération
        /// </summary>
        public CodeGenerationEvent GenerationEvent { get; set; }
        /// <summary>
        /// Element sur lequel porte la génération (Peut-être null suivant le type d'événement)
        /// </summary>
        public ModelElement Element { get; set; }
        /// <summary>
        /// Service provider du contexte
        /// </summary>
        public IServiceProvider ServiceProvider { get; private set; }
        /// <summary>
        /// Chemin complet du modéle sur lequel porte la génération
        /// </summary>
        public string ModelFileName { get; private set; }
        /// <summary>
        /// Id de la propriété qui a été modifié
        /// </summary>
        public Guid PropertyId { get; set; }
        /// <summary>
        /// Ancienne valeur de la propriété modifiée
        /// </summary>
        public object OldPropertyValue { get; set; }
        /// <summary>
        /// Stratégie courante
        /// </summary>
        public IGenerationStrategy Strategy { get; private set; }

    }
}
